/*
 * SIT_ToolTip.c : termporary popup window displaying some text.
 *
 * Written by T.Pierron, Dec 09, 2010.
 */

#include "SIT_P.h"
#include <stdio.h>

	TagList TooltipClass[] = {
		{ SIT_SuperClass,  NULL,          ___, SIT_INT,  (ULONG) WidgetClass },
		{ SIT_Styles,      "styles",      _SG, SIT_INT,  OFFSET(SIT_Tooltip, tt_Styles) },
		{ SIT_DisplayTime, "displayTime", _SG, SIT_INT,  OFFSET(SIT_Tooltip, tt_DisplayTime) },
		{ SIT_SubRect,     "subRect",     _SG, SIT_INT,  OFFSET(SIT_Tooltip, tt_SubRect) },
		{ SIT_HeaderText,  "headerText",  _SG, SIT_STR,  OFFSET(SIT_Tooltip, tt_Header) },
		{ SIT_HeaderIcon,  "headerIcon",  _SG, SIT_INT,  OFFSET(SIT_Tooltip, tt_Icon) },
		{ SIT_TagEnd }
	};


/* Group modifications of widget into one call to avoid flicker */
static int SIT_ApplyTooltipStyles(SIT_Widget w, APTR call_data, APTR user_data)
{
	SIT_Tooltip tip = (SIT_Tooltip) w;

	/* Style1: header text/icon */
	if (w->sw_Flags & SITF_Style1Changed)
	{
		LPWSTR str = L"";
		if (tip->tt_Header)
			UTF8ToUTF16(tip->tt_Header, str);
		SendMessage(w->sw_Handle, TTM_SETTITLE, tip->tt_Icon, (LPARAM) str);
		w->sw_Flags &= ~SITF_Style1Changed;
	}

	/* Style2: delay tooltip is displayed */
	if (w->sw_Flags & SITF_Style2Changed)
	{
		int delay = tip->tt_DisplayTime;
		if (delay > 65535) delay = 65535; // Max 65 seconds :-/
		SendMessage(w->sw_Handle, TTM_SETDELAYTIME, TTDT_AUTOPOP, delay);
		w->sw_Flags &= ~SITF_Style2Changed;
	}

	w->sw_PostProcess = NULL;
	return 0;
}

static int SIT_SetTooltipValues(SIT_Widget w, APTR call_data, APTR user_data)
{
	SIT_Variant * value = user_data;
	SIT_Tooltip   tip   = (SIT_Tooltip) w;
	int           isSet = 0;

	switch (((TagList *)call_data)->tl_TagID) {
	case SIT_SubRect:     tip->tt_SubRect     = value->integer; break;
	case SIT_HeaderText:  tip->tt_Header      = value->string;  isSet = SITF_Style1Changed; break;
	case SIT_HeaderIcon:  tip->tt_Icon        = value->integer; isSet = SITF_Style1Changed; break;
	case SIT_DisplayTime: tip->tt_DisplayTime = value->integer; isSet = SITF_Style2Changed; break;
	default: return SIT_SetWidgetValue(w, call_data, user_data); // super class
	}

	if (isSet)
	{
		w->sw_Flags |= isSet;
		w->sw_PostProcess = SIT_ApplyTooltipStyles;
	}
	return 0;
}

/* F..g backward compatibility, has to do that job ourself if tooltip hasn't any title */
static int SIT_GetMaxToolWidth(SIT_Widget w, LPWSTR str)
{
	HDC     hdc = GetDC(w->sw_Handle);
	HGDIOBJ old = SelectObject(hdc, w->sw_Font);
	int     max = 0;
	LPWSTR  p;
	SIZE    sz;

	do {
		for (p = str; *p && *p != '\n'; p ++);
		GetTextExtentPoint32(hdc, str, p - str, &sz);
		if (max < sz.cx) max = sz.cx;
		if (*p) p ++;
		str = p;
	}
	while (*str);
	SelectObject(hdc, old);
	ReleaseDC(w->sw_Handle, hdc);
	return max;
}

/* Control creation */
BOOL SIT_CreateTooltip(SIT_Widget w, va_list args)
{
	SIT_Widget  parent = w->sw_Parent;
	SIT_Tooltip tip = (SIT_Tooltip) w;
	int         style = WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP;
	HWND        hwnd;

	w->sw_Flags |= SITF_TopLevel;
	w->sw_SetValue = SIT_SetTooltipValues;

	/* Default values */
	SIT_ParseTags(w, args, w->sw_Class = TooltipClass);

	if (tip->tt_Styles & SITV_TooltipBalloon) style |= TTS_BALLOON;
	if (tip->tt_Styles & 4) style |= TTS_CLOSE;

	while (parent && parent->sw_Type != SIT_DIALOG)
		parent = parent->sw_Parent;

	hwnd = w->sw_Handle = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
		style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		parent->sw_Handle, NULL, instance, NULL
	);

	if (hwnd)
	{
		HWND     tool = w->sw_Parent->sw_Handle;
		TOOLINFO info = {.cbSize = sizeof info, .uFlags = TTF_IDISHWND | TTF_PARSELINKS,
		                 .uId = (UINT) tool};

		info.uFlags |= (tip->tt_Styles & SITV_TooltipSticky ? TTF_TRACK : TTF_SUBCLASS);

		SIT_SetDefaultFont(w);
		SetProp(hwnd, sit_class, (HANDLE) w);
		UTF8ToUTF16(w->sw_Title, info.lpszText);
		SendMessage(hwnd, TTM_ADDTOOL, 0, (LPARAM) &info);
		SendMessage(hwnd, TTM_SETMAXTIPWIDTH, 0, SIT_GetMaxToolWidth(w, info.lpszText));
		tip->tt_Parent = w->sw_Parent;

		/* Reparent the control to avoir useless steps for layout manager */
		if (w->sw_Parent != parent)
		{
			ListRemove(&w->sw_Parent->sw_Children, &w->sw_Node);
			ListAddTail(&parent->sw_Children, &w->sw_Node);
			w->sw_Parent = parent;
		}

		RECT rect = {.left = w->sw_Margins[0], .top = w->sw_Margins[1], .right = w->sw_Margins[2], .bottom = w->sw_Margins[3]};

		SendMessage(hwnd, TTM_SETMARGIN, 0, (LPARAM) &rect);

		if (w->sw_PostProcess)
			w->sw_PostProcess(w, NULL, NULL);

		return TRUE;
	}
	else return FALSE;
}

#define	tip  ((SIT_Tooltip)w)
#define	dlg  ((SIT_Dialog)d)

static int SIT_HideTooltip(SIT_Widget d, APTR cd, APTR w)
{
	ReleaseCapture();
	SendMessage(dlg->sd_Tooltip->sw_Handle, TTM_POP, 0, 0);
	dlg->sd_ToolTimerID = 0;
	return 0;
}

DLLIMP void SIT_ShowTooltip(SIT_Widget w)
{
	Rect *   rect = &tip->tt_Parent->sw_Box;
	HANDLE   tool = tip->tt_Parent->sw_Handle;
	TOOLINFO info = {.cbSize = sizeof info, .uId = (UINT) tool};
	POINT    pt;

	pt.x = (rect->width  - rect->x) / 2;
	pt.y = (rect->height - rect->y) / 2;

	ClientToScreen(tool, &pt);

	SendMessage(w->sw_Handle, TTM_GETTOOLINFO, 0, (LPARAM) &info);
	SIT_Dialog d = (SIT_Dialog) w->sw_Parent;

	if (d->sd_Tooltip)
		SendMessage(d->sd_Tooltip->sw_Handle, TTM_POP, 0, 0);

	if (tip->tt_Styles & SITV_TooltipSticky)
	{
		SetCapture(d->super.sw_Handle);
		if (tip->tt_DisplayTime >= 0)
		{
			int delay = tip->tt_DisplayTime;
			if (delay == 0) delay = GetDoubleClickTime() * 10;
			d->sd_ToolTimerID = SIT_SetTimer(&d->super, SIT_HideTooltip, w, delay);
		}
	}

	d->sd_Tooltip = w;
	SendMessage(w->sw_Handle, TTM_TRACKACTIVATE, False, (LPARAM) &info);
	SendMessage(w->sw_Handle, TTM_TRACKPOSITION, 0, (pt.y<<16)|pt.x);
	SendMessage(w->sw_Handle, TTM_TRACKACTIVATE, True, (LPARAM) &info);
}

APTR SIT_CreateTip(SIT_Widget parent, STRPTR fmt)
{
	int    len  = WideCharToMultiByte(CP_UTF8, 0, parent->sw_Name, -1, NULL, 0, NULL, NULL);
	STRPTR name = alloca(len+1);

	name[0] = 't';
	WideCharToMultiByte(CP_UTF8, 0, parent->sw_Name, -1, name + 1, len, NULL, NULL);

	SIT_Widget ret = SIT_CreateWidget(name, SIT_TOOLTIP, parent, SIT_Title, fmt, NULL);
	free(fmt);
	return ret;
}

#undef tip
#undef dlg
